package org.tr.demo.clock;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

//////////////////////////////////////////////////////////////// Clock class
class AnalogClock extends JComponent {
    
    //============================================================ constants
    private static final double TWO_PI   = 2.0 * Math.PI;
    
    private static final int    UPDATE_INTERVAL = 1000;  // Millisecs
    private List<Integer> list = new ArrayList<Integer>();
    
    //=============================================================== fields
    private Calendar _now = Calendar.getInstance();  // Current time.
    
    private int _diameter;                 // Height and width of clock face
    private int _centerX;                  // x coord of middle of clock
    private int _centerY;                  // y coord of middle of clock
    private BufferedImage _clockImage;     // Saved image of the clock face.
    
    private javax.swing.Timer _timer;      // Fires to update clock.
    
    //==================================================== Clock constructor
    public AnalogClock() {
        setPreferredSize(new Dimension(600,600));
        
        _timer = new javax.swing.Timer(UPDATE_INTERVAL, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
            	for (int i=0; i<1024; i++) {
                	list.add(i);
                }
            	updateTime();
                repaint();              
            }
        });

    }
    
    //================================================================ start
    /** Start the timer. */
    public void start() {
        _timer.start(); 
    }
    
    //================================================================= stop
    /** Stop the timer. */
    public void stop() {
        _timer.stop(); 
    }
    
    //=========================================================== updateTime
    private void updateTime() {
        //... Avoid creating new objects.
        _now.setTimeInMillis(System.currentTimeMillis());
        //System.out.println(new Date(_now.getTimeInMillis()));
    }
    
    //======================================================= paintComponent
    @Override public void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
        
        //... The panel may have been resized, get current dimensions
        int w = getWidth();
        int h = getHeight();
        _diameter = ((w < h) ? w : h);
        _centerX = _diameter / 2;
        _centerY = _diameter / 2;
        
        //... Create the clock face background image if this is the first time,
        //    or if the size of the panel has changed
        if (_clockImage == null
                || _clockImage.getWidth() != w
                || _clockImage.getHeight() != h) {
            _clockImage = (BufferedImage)(this.createImage(w, h));
            
            //... Get a graphics context from this image
            Graphics2D g2a = _clockImage.createGraphics();
            g2a.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                 RenderingHints.VALUE_ANTIALIAS_ON);
            drawClockFace(g2a);
        }
        
        //... Draw the clock face from the precomputed image
        g2.drawImage(_clockImage, null, 0, 0);
        
        //... Draw the clock hands dynamically each time.
        drawClockHands(g2);
        
        //Calendar cal = Calendar.getInstance();
        //Date date = cal.getTime();
        //int fontSize = 20;
        //g.setFont(new Font("TimesRoman", Font.PLAIN, fontSize));
        //DateFormat dateFormatter = DateFormat.getDateTimeInstance();
        //g.drawString(dateFormatter.format(new Date()), 5, h-20);
      
    }
    
    //====================================== convenience method drawClockHands
    private void drawClockHands(Graphics2D g2) {
        //... Get the various time elements from the Calendar object.
        int hours   = _now.get(Calendar.HOUR);
        int minutes = _now.get(Calendar.MINUTE);
        int seconds = _now.get(Calendar.SECOND);
        int millis  = _now.get(Calendar.MILLISECOND);
        
        //... second hand
        int handMin = _diameter / 8;    // Second hand doesn't start in middle.
        int handMax = _diameter / 2;    // Second hand extends to outer rim.
        double fseconds = (seconds + (double)millis/1000) / 60.0;
        //drawRadius(g2, fseconds, 0, handMax);
        
        //... minute hand
        handMin = 0;                    // Minute hand starts in middle.
        handMax = _diameter / 3; 
        double fminutes = (minutes + fseconds) / 60.0;
        //drawRadius(g2, fminutes, 0, handMax);
        
        //... hour hand
        handMin = 0;
        handMax = _diameter / 4;
        drawRadius(g2, (hours + fminutes) / 12.0, 0, handMax);
    }
    
    //======================================= convenience method drawClockFace
    private void drawClockFace(Graphics2D g2) {
        // ... Draw the clock face.  Probably into a buffer.        
        g2.setColor(Color.GRAY);
        g2.fillOval(0, 0, _diameter, _diameter);
        g2.setColor(Color.BLACK);
        g2.drawOval(0, 0, _diameter, _diameter);
        
        int radius = _diameter / 2;
        
        //... Draw the tick marks around the circumference.
        for (int sec = 0; sec < 60; sec++) {
            int tickStart;
            if (sec%5 == 0) {
                tickStart = radius - 10;  // Draw long tick mark every 5.
            } else {
                tickStart = radius - 5;   // Short tick mark.
            }
            drawRadius(g2, sec / 60.0, tickStart , radius);
        }
    }
    
    //==================================== convenience method drawRadius
    // This draw lines along a radius from the clock face center.
    // By changing the parameters, it can be used to draw tick marks,
    // as well as the hands.
    private void drawRadius(Graphics2D g2, double percent,
                            int minRadius, int maxRadius) {
        //... percent parameter is the fraction (0.0 - 1.0) of the way
        //    clockwise from 12.   Because the Graphics2D methods use radians
        //    counterclockwise from 3, a little conversion is necessary.
        //    It took a little experimentation to get this right.
        double radians = (0.5 - percent) * TWO_PI;
        double sine   = Math.sin(radians);
        double cosine = Math.cos(radians);
        
        int dxmin = _centerX + (int)(minRadius * sine);
        int dymin = _centerY + (int)(minRadius * cosine);
        
        int dxmax = _centerX + (int)(maxRadius * sine);
        int dymax = _centerY + (int)(maxRadius * cosine);
        g2.setStroke(new BasicStroke(3));
        g2.drawLine(dxmin, dymin, dxmax, dymax);
    }
}
